home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Netware Super Library
/
Netware Super Library.iso
/
benchmrk
/
stp_nd
/
nx.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-04-24
|
27KB
|
918 lines
/*
$Module NX.C$
Copyright 1990
By NetFRAME Systems Inc.
Sunnyvale, California U.S.A.
$Author: Karl S. Johnson $
$Date: 03 Apr 1990 11:54:02 $
$Revision: 1.2 $
$Description$
This is a NetWare Loadable Module to measure network performance.
$EndDescription$
Revision History
$Log: H:/386/NLMS/DX/SRC/VCS/NX.C $
*
* Rev 1.2 03 Apr 1990 11:54:02 Karl S. Johnson
* Recode scheduler in exerciser routine to clean up and to go to
* sleep when there is nothing to do.
*
* Rev 1.1 02 Apr 1990 17:15:32 Karl S. Johnson
* Various changes to make it work the first time on System Pro and NetFRAME
*
* Rev 1.0 21 Mar 1990 10:48:46 Walter A. Wallach
* Initial revision.
*
*/
#include "procdefs.h"
#include "ecb.h"
#include "loader.h"
#include "lanconf.h"
#include "random.h"
#define MAX_DEVICES 16
#define MAX_SENDS_PER_DEVICE 32
#define DEVICES_PER_PAGE 10
#define NX_PRIORITY 50
#define NX_SIGNATURE "NX TEST PACKET"
#define STACK_SIZE 2048*16
#define _UNUSED(x) if (0) if (x)
extern LONG NumberOfPollingLoops, MaximumNumberOfPollingLoops;
LONG NXUpdateInterval;
ScreenStruct *nXerciseScreen;
int DeviceCount = 0;
BYTE *stack; /* NX Monitor Stack */
LONG stackSize;
BYTE *NXStack = NULL; /* NX Exerciser Stack */
LONG NXActualStackSize;
LONG nXerciseModuleHandle;
LONG ServerProcessPriority = 50;
LONG NXMonitorProcessID = 0;
LONG NXerciseProcessID = 0;
LONG NXChunksPerIO;
LONG NXMaxSendsPerDevice;
LONG NXSleeping = 0;
LONG NXWakeRequested = 0;
char NXMonitorStatus = 'I'; /* Possible Status I=Initializing R=Running P=Pending Stop S=Stopped */
eventcontrolblock *ECBList = NULL;
struct DeviceData
{
int OutstandingIOs;
int Index;
int BoardNumber;
int RecieverRegistered;
LONG Random;
BYTE ActivityType; /* 'T' = Transmit 'R' = Recieve 'B' = Both */
BYTE Name[80];
} Device[MAX_DEVICES];
/* NOTE: In order to prevent overflow of certain performance counters, byte
counts are maintained in units of 64 bytes (1 * 2^6) called "Chunks".
To convert Chunks to Kilobytes divide by 16.
*/
#define CHUNK_SIZE 64
#define CHUNK_TO_KB 16
#define MAX_PACKET_CHUNKS ( 1500 / CHUNK_SIZE )
struct PerformanceData
{
LONG TotalReceivesCompleted;
LONG TotalChunksReceived;
LONG CurrentReceivesCompleted;
LONG CurrentChunksReceived;
LONG TotalSendsCompleted;
LONG TotalChunksSent;
LONG CurrentSendsCompleted;
LONG CurrentChunksSent;
} Performance[MAX_DEVICES];
struct PerformanceData Aggregate;
int AggregateOutstandingIOs = 0;
int BoardToDeviceIndex[MAX_DEVICES];
BYTE CommonBuffer[2000];
/* debug */
eventcontrolblock *SendECB[MAX_DEVICES*32];
LONG SendECBCount= 0;
/* debug */
void
NXSendCompletion( eventcontrolblock *currentECB );
LONG
NXReceiveCompletion( eventcontrolblock *currentECB );
void
MakeDeviceDescription( LONG BoardNumber, BYTE *buffer);
void
NXercise();
void
NXMonitor();
/* LSL Interface routines */
LONG CLSLRegisterPreScanStack( int BoardNumber,
int HandlerProcedure(),
int ControlProcedure() );
LONG CLSLDeRegisterPreScanStack( int BoardNumber );
void *CLSLGetECB();
void CLSLReturnECB( void *ECB );
extern NXReceiveDone();
extern NXSendDone();
extern NXControl();
LONG
StartProcedure(
LONG moduleHandle,
ScreenStruct *initializationErrorScreen,
BYTE *commandLine,
BYTE *loadDirectoryPath,
LONG unitializedDataLength,
LONG fileHandle,
LONG (*ReadRoutine)(LONG handle, LONG offset, BYTE *buffer, LONG length),
LONG customDataOffset,
LONG customDataSize)
{
static BYTE nXerciseScreenName[] = "NX Screen";
int i;
BYTE *Token;
_UNUSED(commandLine);
_UNUSED(loadDirectoryPath);
_UNUSED(unitializedDataLength);
_UNUSED(fileHandle);
_UNUSED(ReadRoutine);
_UNUSED(customDataOffset);
_UNUSED(customDataSize);
for (Token = commandLine; *Token != '\000'; Token++)
{
if (*Token == 'D') EnterDebugger();
}
for ( i = 0; i < MAX_DEVICES; i++ ) BoardToDeviceIndex[i] = -1;
CSetB( 0, CommonBuffer, sizeof( CommonBuffer ) );
CStrCpy( CommonBuffer, NX_SIGNATURE );
stack = GetNonMovableMemory(STACK_SIZE, &stackSize);
if (stack == NULL)
{
OutputToScreen(initializationErrorScreen,
"NX: Unable to get memory for stack\r\n");
goto Error0;
}
nXerciseModuleHandle = moduleHandle;
if (OpenScreen(nXerciseScreenName, &nXerciseScreen) != 0)
{
OutputToScreen(initializationErrorScreen,
"NX: Unable to open NX screen\r\n");
goto Error1;
}
/* The variable stackSize contains the amount of memory actually
allocated for the stack, so use it instead of STACK_SIZE.*/
/* this should be the last thing we do */
NXMonitorProcessID = CCreateProcess(NX_PRIORITY, NXMonitor,
stack + stackSize, stackSize, "NXMon");
while ( NXMonitorStatus == 'I') CRescheduleLast();
switch ( NXMonitorStatus)
{
case 'R':
break;
case 'S':
default:
OutputToScreen( systemConsoleScreen,
"Failed to start NX monitor process\r\n" );
goto Error3;
}
return (0);
/* Error Recovery */
Error3:
CloseScreen(nXerciseScreen);
Error1:
ReturnNonMovableMemory(stack);
Error0:
return (-1);
}
void ExitProcedure(void)
{
int i;
eventcontrolblock *ECBp;
if ( NXMonitorProcessID != 0 ) CDestroyProcess( NXMonitorProcessID );
if ( NXMonitorStatus != 'S' ) /* if not already stopped - stop */
{
NXMonitorStatus = 'S';
while ( AggregateOutstandingIOs != 0 ) CRescheduleLast();
if ( NXerciseProcessID != 0 ) CDestroyProcess( NXerciseProcessID );
}
CloseScreen( nXerciseScreen );
for (i=0; i < DeviceCount; i++)
{
if ( Device[i].RecieverRegistered )
{
CLSLDeRegisterPreScanStack (Device[i].BoardNumber);
}
while ( ECBList != NULL )
{
ECBp = ECBList;
ECBList = ECBp->RLink;
/* debug */ if ( (LONG)ECBList == 0xFFFFFFFF ) EnterDebugger();
/* Return the ECB to the OS */
CLSLReturnECB( ECBp );
}
}
if ( NXStack != NULL ) ReturnNonMovableMemory( NXStack );
ReturnNonMovableMemory( stack );
}
void NXExit(void)
{
KillMe((struct LoadDefinitionStructure *)nXerciseModuleHandle);
/* Sleep forever until the exit procedure kills this process */
for (;;)
CSleepUntilInterrupt();
}
void
NXMonitor()
{
long int LStatus;
int DeviceIndex;
LONG MaxPage;
LONG CurrentPage;
LONG FirstDevice;
LONG LastDevice;
LONG StartTime;
LONG IntervalStartTime;
LONG ElapsedSeconds;
LONG IntervalSeconds;
LONG Tenths;
LONG utilization;
LONG BytesPerIO;
LONG DeviceID;
LONG UpdateTicks;
eventcontrolblock *ECBp;
int i;
LONG chunks;
LONG packets;
BYTE Answer;
BYTE Dummy;
BYTE buffer[200];
RandomNumberCount = sizeof( RandomNumber ) / 4;
/* Activate our screen */
Enable();
ActivateScreen(nXerciseScreen);
/* Tell NXLoad we are Running */
NXMonitorStatus = 'R';
/* Ask for packet size */
InputFromScreen( nXerciseScreen,
"RF",
2,
2,
buffer,
0L,
TRUE,
"F",
"Packet Length Type [F=Fixed R=Random]? " );
if ( buffer[0] == 'F' || buffer[0] == 'f' )
{
PromptForUnsignedNumber( nXerciseScreen,
&BytesPerIO,
CHUNK_SIZE,
MAX_PACKET_CHUNKS * CHUNK_SIZE,
10L,
0L,
TRUE,
64L,
"Bytes per packet [%d:%d]? ",
CHUNK_SIZE,
MAX_PACKET_CHUNKS * CHUNK_SIZE );
NXChunksPerIO = ( BytesPerIO + ( CHUNK_SIZE / 2 )) / CHUNK_SIZE;
if ( ( NXChunksPerIO * CHUNK_SIZE ) != BytesPerIO )
{
OutputToScreen( nXerciseScreen,
"Closest packet size avaiable %d selected\n\r",
NXChunksPerIO * 64 );
}
}
else
{
NXChunksPerIO = 0;
}
/* Ask for queue depth */
PromptForUnsignedNumber( nXerciseScreen,
&NXMaxSendsPerDevice,
1L,
MAX_SENDS_PER_DEVICE,
10L,
0L,
TRUE,
3L,
"Number of concurrent sends to queue per device [1-%d]? ",
MAX_SENDS_PER_DEVICE);
/* Ask for update interval */
PromptForUnsignedNumber( nXerciseScreen,
&NXUpdateInterval,
1L,
60L,
10L,
0L,
TRUE,
5L,
"Screen update interval in seconds [1-60]? ");
ConvertSecondsToTicks( NXUpdateInterval, 0L, &UpdateTicks );
/* Ask for selections or go */
DeviceCount = 0;
for (DeviceID = 0; DeviceID < MAX_DEVICES; DeviceID++)
{
/* test for presence of device */
if ( MLIDLoadedHandleTable[DeviceID] == 0 ) continue;
MakeDeviceDescription( DeviceID, Device[DeviceCount].Name);
LStatus = PromptForYesOrNo( nXerciseScreen,
0L,
TRUE,
"\r\nExercise %s ?",
Device[DeviceCount].Name );
if ( LStatus )
{
/* Build map to map board number to device array index */
BoardToDeviceIndex[DeviceID] = DeviceCount;
InputFromScreen( nXerciseScreen,
"TRB",
2,
2,
buffer,
0L,
TRUE,
"B",
"Device Activity [T=Transmit R=Recieve B=Both]? " );
Device[DeviceCount].Index = DeviceCount;
Device[DeviceCount].BoardNumber = DeviceID;
Device[DeviceCount].ActivityType = buffer[0];
Device[DeviceCount].Random = 0;
Device[DeviceCount].OutstandingIOs = 0;
Device[DeviceCount].RecieverRegistered = 0;
if ( Device[DeviceCount].ActivityType != 'T' ) /* Recieving ? */
{
/* Register stack */
if ( CLSLRegisterPreScanStack( DeviceID, NXReceiveDone, NXControl ) == 0 )
{
Device[DeviceCount].RecieverRegistered = 1;
}
else
{
OutputToScreen( nXerciseScreen, "NX Could not register PreScan reciever for device\r\n");
}
}
if ( Device[DeviceCount].ActivityType != 'R' ) /* Transmitting? */
{
for ( i = 0; i < NXMaxSendsPerDevice; i++ )
{
/* Get an ECB for sending from the OS */
while ( ( ECBp = CLSLGetECB() ) == NULL )
{
/*
OutputToScreen( nXerciseScreen, "NX Could not get a send ECB - trying again\r\n");
*/
Delay ( 5 );
}
/* debug */
SendECB[SendECBCount] = ECBp;
SendECBCount++;
/* debug */
/* Link the ECB into the available queue for the device*/
ECBp->RLink = ECBList;
ECBList = ECBp;
/* debug */ if ( (LONG)ECBList == 0xFFFFFFFF ) EnterDebugger();
/* Setup the send ECB */
ECBp->RESRAddress = (LONG)&NXSendDone;
ECBp->RLogicalID = 0;
ECBp->RImmediateAddress[0] = 0xff;
ECBp->RImmediateAddress[1] = 0xff;
ECBp->RImmediateAddress[2] = 0xff;
ECBp->RImmediateAddress[3] = 0xff;
ECBp->RImmediateAddress[4] = 0xff;
ECBp->RImmediateAddress[5] = 0xff;
ECBp->RSocket = 0;
ECBp->RPacketLength = 0;
ECBp->RFragmentCount = 1;
ECBp->RPacketOffset = (LONG)CommonBuffer;
ECBp->RPacketSize = 0;
}
}
/* Clear performance information */
Performance[DeviceCount].TotalReceivesCompleted = 0;
Performance[DeviceCount].TotalChunksReceived = 0;
Performance[DeviceCount].CurrentReceivesCompleted = 0;
Performance[DeviceCount].CurrentChunksReceived = 0;
Performance[DeviceCount].TotalSendsCompleted = 0;
Performance[DeviceCount].TotalChunksSent = 0;
Performance[DeviceCount].CurrentSendsCompleted = 0;
Performance[DeviceCount].CurrentChunksSent = 0;
DeviceCount++;
}
}
/* Zero aggregate preformance numbers */
Aggregate.TotalReceivesCompleted = 0;
Aggregate.TotalChunksReceived = 0;
Aggregate.CurrentReceivesCompleted = 0;
Aggregate.CurrentChunksReceived = 0;
Aggregate.TotalSendsCompleted = 0;
Aggregate.TotalChunksSent = 0;
Aggregate.CurrentSendsCompleted = 0;
Aggregate.CurrentChunksSent = 0;
AggregateOutstandingIOs = 0;
/* Make sure at least one Device is selected */
if ( DeviceCount < 1 )
{
OutputToScreen( nXerciseScreen,
"No Devices selected\r\n" );
Delay( 91 );
NXExit();
}
/* Start NXercise */
NXStack = GetNonMovableMemory( STACK_SIZE,
&NXActualStackSize );
if ( NXStack == NULL)
{
OutputToScreen ( nXerciseScreen,
"Insufficient memory to start NX subprocess\r\n");
Delay( 91 );
NXExit();
}
NXerciseProcessID = CCreateProcess( NX_PRIORITY - 1,
NXercise,
NXStack + NXActualStackSize,
NXActualStackSize,
"NXerci");
/* Compute pages of displays */
MaxPage = ( DeviceCount / DEVICES_PER_PAGE ) + 1;
CurrentPage = 1;
/* Clear the Screen and setup the title */
ClearScreen( nXerciseScreen );
PositionOutputCursor( nXerciseScreen, 0, 0 );
OutputToScreen( nXerciseScreen,
"NetFRAME Network Test with %d Sends queued per device Page %d of %d",
NXMaxSendsPerDevice,
CurrentPage,
MaxPage );
/* Note the starting time for later computations */
StartTime = CurrentTime;
while (1)
{
/* Sleep for update interval */
IntervalStartTime = CurrentTime;
Delay( UpdateTicks );
/* Test for keyboard key */
if ( CheckKeyStatus( nXerciseScreen ) )
{
/* Get the key and process it */
GetKey( nXerciseScreen, &Dummy, &Answer, &Dummy, &Dummy, 0L );
if ( Answer == 'Q' || Answer =='q' )
{
PositionOutputCursor( nXerciseScreen, 24, 0 );
LStatus = PromptForYesOrNo( nXerciseScreen,
0L,
TRUE,
"Exit Network Exerciser? " );
if ( LStatus )
{
NXMonitorStatus = 'P';
}
}
else
{
if ( Answer > '0' && Answer <= '9' )
{
i = Answer - '0';
if ( i <= MaxPage )
{
CurrentPage = i;
ClearScreen( nXerciseScreen );
PositionOutputCursor( nXerciseScreen, 0, 0 );
OutputToScreen( nXerciseScreen,
"NetFRAME Network Test with %d Sends queued per device Page %d of %d",
NXMaxSendsPerDevice,
CurrentPage,
MaxPage );
}
else RingTheBell();
}
else RingTheBell();
}
}
/* Test for requested stop */
if ( NXMonitorStatus == 'P' )
{
while ( AggregateOutstandingIOs != 0 ) CRescheduleLast();
if ( NXerciseProcessID != 0 )
{
CDestroyProcess( NXerciseProcessID );
NXerciseProcessID = 0;
}
NXMonitorStatus = 'S'; /* Say we are stopped */
ReturnNonMovableMemory( NXStack );
NXStack = NULL;
NXExit();
}
/* Compute and display the numbers */
ConvertTicksToSeconds( ( CurrentTime - StartTime ),
&ElapsedSeconds,
&Tenths );
ConvertTicksToSeconds( ( CurrentTime - IntervalStartTime ),
&IntervalSeconds,
&Tenths );
/* Update cumulative statistics */
for ( DeviceIndex = 0; DeviceIndex < DeviceCount; DeviceIndex++ )
{
chunks = Performance[DeviceIndex].CurrentChunksSent;
Performance[DeviceIndex].TotalChunksSent += chunks;
Aggregate.CurrentChunksSent += chunks;
packets = Performance[DeviceIndex].CurrentSendsCompleted;
Performance[DeviceIndex].TotalSendsCompleted += packets;
Aggregate.CurrentSendsCompleted += packets;
chunks = Performance[DeviceIndex].CurrentChunksReceived;
Performance[DeviceIndex].TotalChunksReceived += chunks;
Aggregate.CurrentChunksReceived += chunks;
packets = Performance[DeviceIndex].CurrentReceivesCompleted;
Performance[DeviceIndex].TotalReceivesCompleted += packets;
Aggregate.CurrentReceivesCompleted += packets;
}
/* Now roll up the aggregate totals */
Aggregate.TotalChunksSent += Aggregate.CurrentChunksSent;
Aggregate.TotalChunksReceived += Aggregate.CurrentChunksReceived;
Aggregate.TotalSendsCompleted += Aggregate.CurrentSendsCompleted;
Aggregate.TotalReceivesCompleted += Aggregate.CurrentReceivesCompleted;
PositionOutputCursor( nXerciseScreen, 1, 0 );
OutputToScreen( nXerciseScreen, "%s\r\n%s\n\r",
" Device Cur. Send Cur. Recv. Ave. Send Ave. Recv.",
" Name KB/s Pkt/s KB/s Pkt/s KB/s Pkt/s KB/s Pkt/s" );
/* 99999 99999 99999 99999 99999 99999 99999 99999 */
FirstDevice = ( CurrentPage - 1 ) * DEVICES_PER_PAGE;
/* note - LastDevice is really last Device index (0 based) plus 1) */
if ( CurrentPage == MaxPage )
{
LastDevice = DeviceCount;
}
else
{
LastDevice = CurrentPage * DEVICES_PER_PAGE;
}
for ( DeviceIndex = FirstDevice; DeviceIndex < LastDevice; DeviceIndex++ )
{
OutputToScreen( nXerciseScreen, "%-20.20s ", Device[DeviceIndex].Name );
OutputToScreen( nXerciseScreen, "%5d %5d %5d %5d %5d %5d %5d %5d\r\n",
( Performance[DeviceIndex].CurrentChunksSent / CHUNK_TO_KB ) / IntervalSeconds,
( Performance[DeviceIndex].CurrentSendsCompleted ) / IntervalSeconds,
( Performance[DeviceIndex].CurrentChunksReceived / CHUNK_TO_KB ) / IntervalSeconds,
( Performance[DeviceIndex].CurrentReceivesCompleted ) / IntervalSeconds,
( Performance[DeviceIndex].TotalChunksSent / CHUNK_TO_KB ) / ElapsedSeconds,
( Performance[DeviceIndex].TotalSendsCompleted ) / ElapsedSeconds,
( Performance[DeviceIndex].TotalChunksReceived / CHUNK_TO_KB ) / ElapsedSeconds,
( Performance[DeviceIndex].TotalReceivesCompleted ) / ElapsedSeconds);
}
/* Aggregate numbers */
OutputToScreen( nXerciseScreen, "\r\n" );
OutputToScreen( nXerciseScreen, "%-20.20s "," All Devices" );
OutputToScreen( nXerciseScreen, "%5d %5d %5d %5d %5d %5d %5d %5d\r\n",
( Aggregate.CurrentChunksSent / CHUNK_TO_KB ) / IntervalSeconds,
( Aggregate.CurrentSendsCompleted ) / IntervalSeconds,
( Aggregate.CurrentChunksReceived / CHUNK_TO_KB ) / IntervalSeconds,
( Aggregate.CurrentReceivesCompleted ) / IntervalSeconds,
( Aggregate.TotalChunksSent / CHUNK_TO_KB ) / ElapsedSeconds,
( Aggregate.TotalSendsCompleted ) / ElapsedSeconds,
( Aggregate.TotalChunksReceived / CHUNK_TO_KB ) / ElapsedSeconds,
( Aggregate.TotalReceivesCompleted ) / ElapsedSeconds);
OutputToScreen( nXerciseScreen, "\r\n" );
/* Utilization */
utilization = 100 - ((NumberOfPollingLoops * 100 +
(MaximumNumberOfPollingLoops >> 1)) / MaximumNumberOfPollingLoops);
OutputToScreen( nXerciseScreen, "Server utilization %6d%%\r\n", utilization);
/* Instructions */
OutputToScreen( nXerciseScreen, "Q to quit or page number to view\n\r" );
/* Zero current counts */
for ( DeviceIndex = 0; DeviceIndex < DeviceCount; DeviceIndex++ )
{
Performance[DeviceIndex].CurrentReceivesCompleted = 0;
Performance[DeviceIndex].CurrentChunksReceived = 0;
Performance[DeviceIndex].CurrentSendsCompleted = 0;
Performance[DeviceIndex].CurrentChunksSent = 0;
}
Aggregate.CurrentReceivesCompleted = 0;
Aggregate.CurrentChunksReceived = 0;
Aggregate.CurrentSendsCompleted = 0;
Aggregate.CurrentChunksSent = 0;
}
}
void
NXercise()
{
int Length;
LONG LStatus;
int CurrentDevice = 0;
LONG SendCount = 0;
LONG BackToBackSends = 0;
register eventcontrolblock *ECBp;
register struct DeviceData *DeviceP;
struct DeviceData *LastDeviceP;
struct DeviceData *WrapDeviceP;
DeviceP = &Device[0];
WrapDeviceP = &Device[DeviceCount];
LastDeviceP = &Device[0];
while (1)
{
if ( NXMonitorStatus != 'R' ) /* If not running go to sleep forever */
/* and wait to be destroyed */
{
while (1) CSleepUntilInterrupt();
}
if ( DeviceP->ActivityType != 'R' ) /* if T or B */
{
if ( DeviceP->OutstandingIOs < NXMaxSendsPerDevice )
{
BackToBackSends++;
SendCount++;
/* Start another IO */
if ( NXChunksPerIO == 0 )
{
/* Random Length Packets */
Length = ( ( RandomNumber[DeviceP->Random] % ( MAX_PACKET_CHUNKS - 1 ) ) + 1 ) * CHUNK_SIZE ;
DeviceP->Random++;
if ( DeviceP->Random == RandomNumberCount )
DeviceP->Random = 0;
}
else
{
Length = NXChunksPerIO * CHUNK_SIZE;
}
/* Build a physical I/O request */
ECBp = ECBList;
ECBList = ECBp->RLink;
/* debug */ if ( (LONG)ECBList == 0xFFFFFFFF ) EnterDebugger();
/* debug */
{
int BAD, i;
BAD = -1;
for ( i = 0; i < SendECBCount; i++ )
{
if ( SendECB[i] == ECBp )
{
BAD = 0;
break;
}
}
if ( BAD ) EnterDebugger();
BAD = -1;
if ( ECBList != NULL )
{
for ( i = 0; i < SendECBCount; i++ )
{
if ( SendECB[i] == ECBList )
{
BAD = 0;
break;
}
}
if ( BAD ) EnterDebugger();
}
};
/* debug */
ECBp->RPacketLength = Length;
ECBp->RPacketSize = Length;
ECBp->RFragmentCount = 1;
ECBp->RBoardNumber = DeviceP->BoardNumber;
ECBp->RESRBXValue = DeviceP->Index;
DeviceP->OutstandingIOs++;
AggregateOutstandingIOs++;
/* Send the ECB */
LStatus = CLSLSendPacket( ECBp );
if ( LStatus != 0 )
{
OutputToScreen( nXerciseScreen, "Send failed - Status 0x%x" );
DeviceP->OutstandingIOs--;
AggregateOutstandingIOs--;
}
}
}
/* Look at the next device */
DeviceP++;
if ( DeviceP == WrapDeviceP ) /* Have all devices been tried */
{
DeviceP = &Device[0]; /* Wrap the device pointer */
if ( SendCount == 0 ) /* Was anything send on this pass? */
{
Disable(); /* No, Nothing could be sent */
NXSleeping = -1; /* Going to sleep */
CSleepUntilInterrupt();
NXSleeping = 0; /* Now awake */
NXWakeRequested = 0;
Enable();
BackToBackSends = 0; /* Note we have taken a break */
}
else
{ /* Yes, Something was sent - keep going */
SendCount = 0;
}
}
if ( BackToBackSends == 20 ) /* Do we need to take a break? */
{
CRescheduleLast(); /* Give someone else a chance */
BackToBackSends = 0; /* Note we have taken a break */
}
}
}
void
NXSendCompletion( eventcontrolblock *currentECB )
{
int i;
int chunks;
register eventcontrolblock *ECBp;
/* debug */
int BAD = -1;
for ( i = 0; i < SendECBCount; i++ )
{
if ( SendECB[i] == currentECB )
{
BAD = 0;
break;
}
}
if ( BAD ) EnterDebugger();
/* debug */
i = currentECB->RESRBXValue;
chunks = ( currentECB->RPacketLength ) / CHUNK_SIZE;
/* Update individual device counts */
Performance[i].CurrentSendsCompleted++;
Performance[i].CurrentChunksSent += chunks;
/* Put the request back on the send queue for the device */
--AggregateOutstandingIOs;
--Device[i].OutstandingIOs;
ECBp = ECBList;
ECBList = currentECB;
/* debug */ if ( (LONG)ECBList == 0xFFFFFFFF ) EnterDebugger();
currentECB->RLink = ECBp;
if ( NXSleeping && (!NXWakeRequested) )
{
NXWakeRequested = -1;
CRescheduleFromInterrupt(NXerciseProcessID);
}
}
LONG
NXReceiveCompletion( eventcontrolblock *currentECB )
{
int i;
int chunks;
/* the board number to device index should be computed here */
i = BoardToDeviceIndex[currentECB->RBoardNumber];
if ( i != -1 ) /* Do we know about this board? */
{
chunks = ( currentECB->RPacketLength ) / CHUNK_SIZE;
/* Update individual device counts */
Performance[i].CurrentReceivesCompleted++;
Performance[i].CurrentChunksReceived += chunks;
/* Now return the receive ECB back to the pool if it's a NX packet */
if ( CStrCmp( (void *)currentECB->RPacketOffset, NX_SIGNATURE ) == 0 )
{
CLSLReturnECB( (void *)currentECB );
return ( 0 ); /* Don't try to route the packet */
}
}
return ( 1 ); /* Attempt to route the packet to a protocol stack */
};
void
MakeDeviceDescription(
LONG boardNumber,
BYTE *buffer)
{
struct DriverConfigurationStructure *lanInfo;
BYTE *ptr;
lanInfo = MLIDConfigurationTable[boardNumber];
ptr = buffer;
/* LAN name */
sprintf(ptr, "%S", MLIDLoadedHandleTable[boardNumber]->LDFileName);
while (*ptr != '.' && *ptr != 0) ptr++;
*ptr++ = ' ';
*ptr++ = '[';
if (PS2Flag)
{
/* slot */
sprintf(ptr, "slot=%x ", lanInfo->DSlot);
ptr = ptr + CStrLen(ptr);
}
else
{
/* IO ports */
if (lanInfo->DIOPortsAndRanges[1] > 0) /* using IO port 0 */
{
sprintf(ptr, "port=%x ", lanInfo->DIOPortsAndRanges[0]);
ptr = ptr + CStrLen(ptr);
}
if (lanInfo->DIOPortsAndRanges[3] > 0) /* using IO port 1 */
{
sprintf(ptr, "port=%x ", lanInfo->DIOPortsAndRanges[2]);
ptr = ptr + CStrLen(ptr);
}
/* memory addresses */
if (lanInfo->DMemoryDecodeAndLength[0].LANMemoryAddress > 0) /* using memory 0 */
{
sprintf(ptr, "mem=%x ",
lanInfo->DMemoryDecodeAndLength[0].LANMemoryAddress);
ptr = ptr + CStrLen(ptr);
if (lanInfo->DMemoryDecodeAndLength[1].LANMemoryAddress > 0) /* using memory 1 */
{
sprintf(ptr, "mem=%x ", lanInfo->DMemoryDecodeAndLength[1].LANMemoryAddress);
ptr = ptr + CStrLen(ptr);
}
}
/* interrupts */
if (lanInfo->DIntLine[0] != 0xff) /* first interrupt */
{
sprintf(ptr, "int=%x ", lanInfo->DIntLine[0]);
ptr = ptr + CStrLen(ptr);
if (lanInfo->DIntLine[1] != 0xff) /* second interrupt */
{
sprintf(ptr, "int=%x ", lanInfo->DIntLine[1]);
ptr = ptr + CStrLen(ptr);
}
}
/* DMA channels */
if (lanInfo->DDMALine[0] != 0xff) /* first DMA */
{
sprintf(ptr, "dma=%x ", lanInfo->DDMALine[0]);
ptr = ptr + CStrLen(ptr);
if (lanInfo->DDMALine[1] != 0xff) /* second DMA */
{
sprintf(ptr, "dma=%x ", lanInfo->DDMALine[1]);
ptr = ptr + CStrLen(ptr);
}
}
}
*(ptr - 1) = ']';
}